﻿using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text;

namespace FastData.DataProvider
{
    public class SqlProviderFactory : DataProviderFactory
    {
        public override string ProviderName
        {
            get { return "System.Data.SqlClient"; }
        }

        internal override string CreateFunctionText(Function query, ExecuteType type)
        {
            if (type == ExecuteType.Reader)
            {
                return "SELECT * FROM " + base.CreateFunctionText(query, type);
            }
            else if (type == ExecuteType.Scalar)
            {
                return "SELECT " + base.CreateFunctionText(query, type);
            }
            else
            {
                throw new NotSupportedException(type.ToString());
            }
        }
        
        internal override string CreateSelectText(QueryBase query, ExecuteType type)
        {
            string from = GetDbObjectName(query.TableName);
            foreach (var join in query.Joins)
            {
                from += " " + join.Type.GetName() + " JOIN " + GetDbObjectName(join.TableName) + " ON " + join.Where;
            }
            
            if (query.SkipCount == 0)
            {
                return "SELECT " + (query.IsDistinct ? "DISTINCT " : "") + (query.TakeCount > 0 ? "TOP " + query.TakeCount + " " : "") + query.FieldNames + " FROM " + from + " " + query.WhereText + " " + query.OrderByText;
            }
            if (query.Data.ServerVersion.StartsWith("11."))
            {
                return "SELECT " + (query.IsDistinct ? "DISTINCT " : "") + query.FieldNames + " FROM " + from + " " + query.WhereText + " " + query.OrderByText + " OFFSET " + query.SkipCount + " ROWS FETCH NEXT " + query.TakeCount + " ROWS ONLY";
            }
            return "SELECT " + (query.IsDistinct ? "DISTINCT " : "") + (query.TakeCount > 0 ? "TOP " + query.TakeCount + " " : "") + query.FieldNames + " FROM " +
                "(SELECT ROW_NUMBER() OVER (" + (string.IsNullOrEmpty(query.OrderByText) ? "ORDER BY " + query.FieldNames : query.OrderByText) + ") AS [FastDataRowNumber]," + query.FieldNames + " FROM " + from + " " + query.WhereText + ") AS [Extent1]" +
                "WHERE [FastDataRowNumber] >" + query.SkipCount;
        }

        public override string GetDbObjectName(string name)
        {
            name = name.Trim();
            if (name == "*" || name.IndexOf('(') > 0 || name.IndexOf(' ') > 0)
            {
                return name;
            }

            return string.Join(".", name.Split('.').Select(n => n[0] == '[' ? n : "[" + n + "]"));
        }

        public override string GetDbParameterName(string name)
        {
            return "@" + name;
        }

        internal override string CreateInsertText(QueryBase query, ExecuteType type)
        {
            string insertText = base.CreateInsertText(query, type);
            if (type != ExecuteType.NoneQuery)
            {
                insertText += ";" + LastIdentityText + ";";
            }
            return insertText;
        }

        public override SelectQuery GetViewTableUsage(DataAccess data, string viewName)
        {
            return data.Select("Table_Name").From("INFORMATION_SCHEMA.VIEW_TABLE_USAGE").Where("View_Name", viewName);
        }

        public override bool SupportBatchCommand
        {
            get { return true; }
        }

        public override bool SupportInsertedId
        {
            get { return true; }
        }

        internal override string LastIdentityText
        {
            get { return "SELECT SCOPE_IDENTITY()"; }
        }
    }

}
